#include "AiLogicUtility.h"
#include "Character/Creature.h"
#include "base/core/gamemath.h"

#include "Character/monster/Monster.h"
#include "Scene/Map.h"
#include "base/core/random.h"
#include "Scene/MapMgr.h"
#include <algorithm>

bool AiLogicUtility::GetChasePoint(int mapId, const float fMinRange, const float fMaxRange, const Point3<float>& dest, const float angle, Point3<float>& chasePoint)
{
	float fRdDis = (fMaxRange - fMinRange) * UtilRandomFloat(1.0f) + fMinRange - fMinRange * UtilRandomFloat(0.5f);
	float fRdDis_X = fRdDis * cosf(angle);
	float fRdDis_Z = fRdDis * sinf(angle);

	Point3<float> tempPos;
	tempPos.x = dest.x - fRdDis_X;
	tempPos.z = dest.z - fRdDis_Z;
	tempPos.y = dest.y;

	return GetNearstPos(mapId, tempPos, chasePoint);
}

bool AiLogicUtility::GetDestAndAngle(Creature* pSrc, Creature* pTarget, Point3<float>& destPos, float& angle, int& area)
{
	Point3<float> srcPos = pSrc->GetPos();
	destPos = pTarget->GetPos();

	angle = GetDotAngle(srcPos.z, srcPos.x, destPos.z, destPos.x) + MMO_PI_2 * (UtilRandomFloat(1.0f) - UtilRandomFloat(1.0f));
	return true;
}

bool AiLogicUtility::ComputeTrackPoint(int mapId, const Point3<float>& srcPos, const Point3<float>& targetPos, const float fTrackRadius, Point3<float>& destPos)
{
	Point3<float> tmpPos = targetPos;

	for(int i = 0; i < 5; i++)
	{
		float angle = GetDotAngle(srcPos.z, srcPos.x, targetPos.z, targetPos.x) + MMO_PI_2 * (UtilRandomFloat(1.0f) - UtilRandomFloat(1.0f));
		float fRdDis_X = fTrackRadius * 0.5f * cosf(angle);
		float fRdDis_Z = fTrackRadius * 0.5f * sinf(angle);

		tmpPos.x -= fRdDis_X;
		tmpPos.z -= fRdDis_Z;
		tmpPos.y = targetPos.y;

		if (GetNearstPos(mapId, tmpPos, destPos))
		{
			return true;
		}
	}
	return false;
}

Point3<float> AiLogicUtility::GetRandomPosInStraightCircle(uint32_t mapId, const Point3<float>& srcPos, const Point3<float>& targetPos, float radius, float angle)
{
	Point3<float> dir = srcPos - targetPos;
	dir.y = 0;
	float dict = dir.length();
	if (dict == 0.0f)
	{
		return srcPos;
	}
	dir = dir / dict;

	Point3<float> destPos;
	Map* pMap = g_GetMapMgr()->GetMap(mapId);
	int count = 5;
	while (count-- > 0)
	{
		angle = Random(0,angle*1000)/1000.0f - angle/2.0f;
		Point3<float> pos;
		pos.y = dir.y;
		pos.x = dir.x * cos(AngleToRadian(angle)) + dir.z * sin(AngleToRadian(angle));
		pos.z = dir.z * cos(AngleToRadian(angle)) - dir.x * sin(AngleToRadian(angle));

		pos = targetPos + pos * radius;
		pos.y = targetPos.y;

		bool ret = pMap->FindNearestPos(pos.x, pos.z, pos.y, &destPos.x, &destPos.z, &destPos.y, nullptr);
		if (!ret)
		{
			continue;
		}

		break;
	}
	return destPos;
}

Point3<float> AiLogicUtility::GetRandomPosInStraightCircle180(uint32_t mapId, const Point3<float>& srcPos, const Point3<float>& targetPos, float radius)
{
	Point3<float> destPos;

	float pi = (float)3.1415926;

	float dictX = srcPos.x - targetPos.x;
	float dictZ = srcPos.z - targetPos.z;
	float dict = sqrt(dictX*dictX + dictZ*dictZ);
	float cosAngle = acos(dictX / dict); //弧度
	float startAngle = pi / 4 * -1;
	float endAngle = pi / 4;

	if (dictZ > 0)
	{
		startAngle += cosAngle;
		endAngle += cosAngle;
	}
	else
	{
		startAngle += cosAngle + (pi - cosAngle) * 2;
		endAngle += cosAngle + (pi - cosAngle) * 2;
	}

	startAngle += 2 * pi;
	endAngle += 2 * pi;

	Map* pMap = g_GetMapMgr()->GetMap(mapId);

	Point3<float> randomPos;
	int count = 2;
	while (count-- > 0)
	{
		float randomAngle = Random((uint32_t)(startAngle * 1000), (uint32_t)(endAngle * 1000)) / 1000.0f;

		randomPos.x = targetPos.x + radius * cos(randomAngle);
		randomPos.y = targetPos.y;
		randomPos.z = targetPos.z + radius * sin(randomAngle);

		bool ret = pMap->FindNearestPos(randomPos.x, randomPos.z, randomPos.y, &destPos.x, &destPos.z, &destPos.y, nullptr);
		if (!ret)
		{
			continue;
		}

		break;
	}

	return destPos;
}

//在以srcPos为中心，以radiux为半径的圆里面找个位置
bool AiLogicUtility::GetRandomPosInCircle(uint32_t mapId, const Point3<float>& srcPos, float radius, Point3<float>& destPos)
{
	const float r = UtilRandomFloat(radius);
	const float angle = UtilRandomFloat(MMO_PI2);

	Point3<float> pos;
	pos.x = srcPos.x + r * cosf(angle);
	pos.z = srcPos.z + r * sinf(angle);
	pos.y = srcPos.y;

	return GetNearstPos(mapId, pos, destPos);
}

//在以srcPos为中心，以radiux为半径的圆上找个位置
bool AiLogicUtility::GetRandomPosOnCircle(uint32_t mapId, const Point3<float>& srcPos, float radius, Point3<float>& destPos)
{
	const float r = radius;
	const float angle = UtilRandomFloat(MMO_PI2);

	Point3<float> pos;
	pos.x = srcPos.x + r * cosf(angle);
	pos.z = srcPos.z + r * sinf(angle);
	pos.y = srcPos.y;

	return GetNearstPos(mapId, pos, destPos);
}

//在以srcPos为中心，以radiux为半径的圆里面找个位置
Point3<float> AiLogicUtility::GetRandomPosInCircle(uint32_t mapId, const Point3<float>& srcPos, float radius)
{
	Map* pMap = g_GetMapMgr()->GetMap(mapId);

	Point3<float> destPos;
	if (pMap == nullptr)
	{
		return destPos;
	}

	float littleRadiux = Random(0, radius * 1000) / 1000.0f;
	float randomAngle = Random(0, MMO_PI2 * 1000) / 1000.0f;

	float x = srcPos.x + littleRadiux * cos(randomAngle);
	float y = srcPos.y;
	float z = srcPos.z + littleRadiux * sin(randomAngle);

	float x1 = 0.0f;
	float y1 = 0.0f;
	float z1 = 0.0f;

	bool ret = pMap->FindNearestPos(x, z, y, &x1, &z1, &y1, nullptr);
	if (ret == false)
	{
		return destPos;
	}

	destPos.x = x1;
	destPos.y = y1;
	destPos.z = z1;

	return destPos;
}

//在以srcPos为中心，以radiux为半径的圆上找个位置
Point3<float> AiLogicUtility::GetRandomPosOnCircle(uint32_t mapId, const Point3<float>& srcPos, float radius)
{
	Map* pMap = g_GetMapMgr()->GetMap(mapId);

	Point3<float> destPos;
	if (pMap == nullptr)
	{
		return destPos;
	}

	int count = 2;
	while (count-- > 0)
	{
		float randomAngle = Random(0, 2 * 3.1415926 * 1000) / 1000.0f;

		float x = srcPos.x + radius * cos(randomAngle);
		float y = srcPos.y;
		float z = srcPos.z + radius * sin(randomAngle);

		float x1 = 0.0f;
		float y1 = 0.0f;
		float z1 = 0.0f;

		bool ret = pMap->FindNearestPos(x, z, y, &x1, &z1, &y1, nullptr);
		if (ret == false)
		{
			continue;
		}

		destPos.x = x1;
		destPos.y = y1;
		destPos.z = z1;

		break;
	}

	return destPos;
}

//在srcPos到targetPos的线上找到一个距离targetPos，radiux远的位置
Point3<float> AiLogicUtility::GetPosInStraight(uint32_t mapId, const Point3<float>& srcPos, const Point3<float>& targetPos, float radius)
{
	Point3<float> dir = srcPos - targetPos;
	float dict = point3Length(targetPos, srcPos);
	if (dict == 0.0f)
	{
		return srcPos;
	}
	dir = dir / dict;
	Point3<float> pos = targetPos + dir * radius;
	return pos;
}

bool AiLogicUtility::GetNearstPos(uint32_t mapId, const Point3<float>& srcPos, Point3<float>& destPos)
{
	Map* pMap = g_GetMapMgr()->GetMap(mapId);
	if (pMap == nullptr)
	{
		return false;
	}
	bool ret = pMap->FindNearestPos(srcPos.x, srcPos.z, srcPos.y, &destPos.x, &destPos.z, &destPos.y, nullptr);
	if (!ret)
	{
		return false;
	}
	return true;
}

Point3<float> AiLogicUtility::GetNearstPos(uint32_t mapId, const Point3<float>& srcPos)
{
	Map* pMap = g_GetMapMgr()->GetMap(mapId);
	Point3<float> targetPos = srcPos;
	if (pMap == nullptr)
	{
		return targetPos;
	}
	bool ret = pMap->FindNearestPos(srcPos.x, srcPos.z, srcPos.y, &targetPos.x, &targetPos.z, &targetPos.y, nullptr);
	if (!ret)
	{
		targetPos = srcPos;
	}
	return targetPos;
}

Point3<float> AiLogicUtility::GetNearstPos(Monster* pMonster)
{
	if (pMonster == nullptr)
	{
		return Point3<float>();
	}
	return GetNearstPos(pMonster->GetMapId(), pMonster->GetPos());
}
